package test.netease.version2.chapter1.lesson1_1_2;

/**
 * 6种线程状态 java.lang.Thread.State
 *
 * 1 New：尚未启动的线程
 *
 * 2 Runable：可运行的线程，等待CPU调度
 *
 * 3 Blocked：线程被阻塞，等待获得监视器(monitor)即锁的线程。————处于synchronized同步代码块或方法中被阻塞
 *
 * 4 Waiting：等待线程的线程状态。下列不带超时的方式：
 *   Object.wait、Thread.join、LockSupport.park
 *
 * 5 Timed Wating：具有指定等待时间的等待的线程。下列带超时的方式：
 *   Thread.sleep、Object.wait、Thread.join、LockSupport.parkNanos、LockSupport.parkUtil
 *
 * 6 Terminated：终止的线程。——线程正常完成或出现异常
 *
 * @author zhangrui
 * @date 2020-04-13 20:41
 * @since 1.0
 */
public class ThreadStateDemo {
    public static Object obj = new Object();

    public static void main(String[] args) throws Exception {
        System.out.println("######### 第一种状态切换 新建->运行->终止 #################");
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread1当前状态:" + Thread.currentThread().getState().toString());
                System.out.println("thread1执行了");
            }
        });
        System.out.println("没调用start方法，thread1当前状态是NEW：" + thread1.getState().toString());
        thread1.start();
        System.out.println("调用start方法，thread1当前状态是RUNNABLE：" + thread1.getState().toString());
        Thread.sleep(2000L);
        System.out.println("主线程等待2秒后，thread1当前状态是（应该已经结束是TERMINATED）：" + thread1.getState().toString());

        System.out.println();
        System.out.println("######### 第二种状态切换 新建->运行->阻塞->终止 #################");
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj){
                    System.out.println("thread2执行了,thread2当前状态:" + Thread.currentThread().getState().toString());
                }

            }
        });
        /**
         * 主线程先拿到锁，thread2 开始等待锁
         */
        synchronized(obj){
            System.out.println("没调用start方法，thread2当前状态是NEW：" + thread2.getState().toString());
            thread2.start();
            System.out.println("调用start方法，thread2当前状态是RUNNABLE：" + thread2.getState().toString());
            Thread.sleep(200L);
            System.out.println("主线程等待0.2秒后，再看thread2当前状态是（应该开始等待锁，是BLOCKED）：" + thread2.getState().toString());
        }
        System.out.println("主线程退出同步块，让出锁");
        Thread.sleep(3000L);
        System.out.println("主线程等待3秒，再看thread2当前状态是（应该已经执行完是TERMINATED）：" + thread2.getState().toString());

        System.out.println();
        System.out.println("######### 第三种状态切换 新建->运行->TIME_WAITING->终止 #################");
        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //thread3启动后，等待1.5秒
                    Thread.sleep(1500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread3执行了,thread3当前状态:" + Thread.currentThread().getState().toString());
            }
        });
        System.out.println("没调用start方法，thread3当前状态是NEW：" + thread3.getState().toString());
        thread3.start();
        System.out.println("调用start方法，thread3当前状态是RUNNABLE：" + thread3.getState().toString());
        Thread.sleep(200L);
        System.out.println("主线程等待0.2秒后，再看thread3当前状态（应该已经调用了sleep，是TIME_WAITING）：" + thread3.getState().toString());
        Thread.sleep(3000L);
        System.out.println("主线程再等待3秒后，再看thread3当前状态是（应该从sleep苏醒已经并执行完，是TERMINATED）：" + thread3.getState().toString());

        //在没有拿到锁的状态下去执行，会抛出java.lang.IllegalMonitorStateException
        //obj.wait();

        System.out.println();
        System.out.println("######### 第四种状态切换 新建->运行->WAITING->终止 #################");
        Thread thread4 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (obj){
                    try {
                        /**
                         * 1 调用wait()方法必须在同步块或者同步方法中进行（synchronized块或者synchronized方法）
                         *   因为如果调用某个对象的wait()方法，当前线程必须拥有这个对象的monitor（即锁）
                         *
                         * 2 调用线程的monitor对象的wait()方法，相当于让线程交出此对象的monitor，然后该线程进入等待状态，
                         *  一直等到后续再次获得此对象的monitor
                         * （Thread类中的sleep方法不同于wait()的是，使当前线程暂停执行一段时间，从而让其他线程有机会继续执行，但它并不释放对象锁）；
                         */
                        System.out.println("thread4 开始休眠1秒，但是不让出锁");
                        Thread.sleep(1000L);
                        System.out.println("thread4 让出监视器");
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        System.out.println("没调用start方法，thread4 当前状态是NEW：" + thread4.getState().toString());
        thread4.start();
        System.out.println("调用start方法，thread4 当前状态是RUNNABLE：" + thread4.getState().toString());
        //让主线程等待一会，确保thread4拿到监视器
        Thread.sleep(200L);
        /**
         * 主线程开始等待监视器
         */
        synchronized (obj){
            System.out.println("主线程拿到监视器后，再看 thread4 当前状态（应该已经让出了锁，是WAITING）：" + thread4.getState().toString());
            Thread.sleep(1000L);
            System.out.println("过1秒之后，主线程把锁还给 thread4");
            obj.notify();
        }
        Thread.sleep(200L);
        System.out.println("再看 thread4 当前状态是（应该已经执行完是TERMINATED）：" + thread4.getState().toString());
    }
}
